package org.opens.websocket;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.telnet.*;
import org.opens.config.ThreadPoolConfig;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/**
 * 功能描述
 *
 * @author: zhangyuming
 * @date: 2023/7/7 11:14
 */
@Slf4j
public class TelnetClientHolder implements Runnable {

    private TelnetClient tc;

    private String ip;

    private int port;

    private String userId;

    private Consumer<String> readResultConsumer;

    private Consumer<String> writeResultConsumer;

    private OutputStream outputStream;

    private InputStream inputStream;

    private final AtomicBoolean endLoop = new AtomicBoolean(true);

    private final AtomicBoolean connected = new AtomicBoolean(false);


    public TelnetClientHolder(String ip, int port, String userId) {
        this.ip = ip;
        this.port = port;
        this.userId = userId;
    }

    public void registerReadHandle(Consumer<String> consumer) {
        this.readResultConsumer = consumer;
    }

    public void registerWriteHandle(Consumer<String> consumer) {
        this.writeResultConsumer = consumer;
    }

    public void connect() {
        try {
            initTelnetClient();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void sendCommand(String command) {
        command += "\n";
        try {
            outputStream.write(command.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();

            if (writeResultConsumer != null) {
                writeResultConsumer.accept(command);
            }
        } catch (IOException e) {
            log.info("用户id({})的telnet命令输入时发生异常!", userId);
        }
    }

    public void close() {
        endLoop.set(false);
        try {
            tc.disconnect();
        } catch (final IOException e) {
            log.info("用户id({})的telnet输出服务线程终止失败.", userId);
        }
    }

    /**
     * 初始化telnet client
     */
    private void initTelnetClient() throws Exception {
        if (connected.get()) {
            return;
        }

        tc = new TelnetClient();

        // 可选类型: VT100、VT52、ANSI 或 VTNT
        // VT52返回结果中不显示颜色, 要不前端会有很多特殊字符
        final TerminalTypeOptionHandler ttopt = new TerminalTypeOptionHandler("VT52", false, false, true, false);
        final EchoOptionHandler echoopt = new EchoOptionHandler(true, false, true, false);
        final SuppressGAOptionHandler gaopt = new SuppressGAOptionHandler(true, true, true, true);

        try {
            tc.addOptionHandler(ttopt);
            tc.addOptionHandler(echoopt);
            tc.addOptionHandler(gaopt);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        tc.connect(ip, port);

        // 线程池处理输入流读取到的结果;
        ThreadPoolConfig.cachedThreadPool.submit(this);

        outputStream = tc.getOutputStream();

        inputStream = tc.getInputStream();

        connected.set(true);
    }

    @Override
    public void run() {
        try {
            final byte[] buff = new byte[1024];
            int ret_read = 0;

            do {
                // 阻塞方法
                ret_read = inputStream.read(buff);
                if (ret_read > 0) {
                    if (readResultConsumer != null) {
                        String result = new String(buff, 0, ret_read);
                        log.info("用户id({})的telnet输出服务线程输出内容: {}", userId, result);
                        readResultConsumer.accept(result);
                    }
                }

            } while (ret_read >= 0 && endLoop.get());
        } catch (final IOException e) {
            log.error("用户id({})的telnet输出服务线程读取数据异常: {}", userId, e.getMessage());
        }
        log.info("用户id({})的telnet输出服务线程已终止.", userId);
    }

}
